﻿namespace PAR.Audio
{
    using System;
    using System.IO;
    using NAudio.Wave;

    class AudioCapture : IDisposable
    {
        private IWaveIn captureDevice;
        private MemoryStream recordedStream;
        private WaveFileWriter writer;

        public bool IsCapturing { get; set; }

        public AudioCapture()
        {
            IsCapturing = false;
            captureDevice = null;
        }

        public void Start(WaveFormat captureFormat)
        {
            if (IsCapturing)
            {
                throw new InvalidOperationException("Already Recording");
            }

            recordedStream = new MemoryStream();
            writer = new WaveFileWriter(new IgnoreDisposeStream(recordedStream), captureFormat);

            captureDevice = new PhoneWaveIn();
            captureDevice.DataAvailable += captureDevice_DataAvailable;
            captureDevice.StartRecording();

            IsCapturing = true;
        }

        public event EventHandler<SampleEventArgs> OnSample;

        void captureDevice_DataAvailable(object sender, WaveInEventArgs e)
        {
            if (!IsCapturing)
                return;

            byte[] buffer = e.Buffer;
            writer.WriteData(buffer, 0, e.BytesRecorded);

            for (int index = 0; index < e.BytesRecorded; index += 2)
            {
                short sample = (short)((buffer[index + 1] << 8) | buffer[index + 0]);
                float sample32 = sample / 32768f;
                if (OnSample != null)
                {
                    OnSample(this, new SampleEventArgs(sample32, 0));
                }
            }
        }

        public void Stop(Stream stream)
        {
            if (!IsCapturing)
            {
                throw new InvalidOperationException("Not Recording");
            }

            captureDevice.StopRecording();
            captureDevice.DataAvailable -= captureDevice_DataAvailable;            
            captureDevice = null;

            writer.Close();
            if (stream != null)
            {
                recordedStream.WriteTo(stream);
            }
            recordedStream.Close();

            writer = null;
            recordedStream = null;

            IsCapturing = false;
        }

        public void Dispose()
        {
            if (IsCapturing)
            {
                Stop(null);
            }
        }
    }
}
